#include <QtGui>

#include "highlighter.h"

Highlighter::Highlighter(QTextDocument *parent)
	: QSyntaxHighlighter(parent)
{
	HighlightingRule rule;

	keywordFormat.setForeground(QColor(0, 0, 160));
	keywordFormat.setFontWeight(QFont::Bold);
	QStringList keywordPatterns;
	keywordPatterns << "\\bchar\\b" << "\\bclass\\b" << "\\bconst\\b"
			<< "\\bdouble\\b" << "\\benum\\b" << "\\bexplicit\\b"
			<< "\\bfriend\\b" << "\\binline\\b" << "\\bint\\b"
			<< "\\blong\\b" << "\\bnamespace\\b" << "\\boperator\\b"
			<< "\\bprivate\\b" << "\\bprotected\\b" << "\\bpublic\\b"
			<< "\\bshort\\b" << "\\bsignals\\b" << "\\bsigned\\b"
			<< "\\bslots\\b" << "\\bstatic\\b" << "\\bstruct\\b"
			<< "\\btemplate\\b" << "\\btypedef\\b" << "\\btypename\\b"
			<< "\\bunion\\b" << "\\bunsigned\\b" << "\\bvirtual\\b"
			<< "\\bvoid\\b" << "\\bvolatile\\b" << "\\bfloat\\b" << "\\breturn\\b"
			<< "\\bif\\b" << "\\belse\\b" << "\\bwhile\\b" << "\\forb\\b"
			<< "\\bbreak\\b" << "\\bcontinue\\b"<< "\\bgoto\\b"<< "\\bauto\\b"
			<< "\\bvolatile\\b" << "\\bswitch\\b" << "\\bcase\\b" << "\\benum\\b"
			<< "\\bextern\\b" << "\\bsizeof\\b" << "\\bdefault\\b"
			<< "\\btrue\\b" << "\\bfalse\\b" << "\\bthis\\b";
	foreach (const QString &pattern, keywordPatterns) {
		rule.pattern = QRegExp(pattern);
		rule.format = keywordFormat;
		highlightingRules.append(rule);
	}

	operaterFormat.setForeground(QColor(255, 0, 0));
	rule.pattern = QRegExp("[!%&*()+-={};<>]|[,]|[?]|[|]|[.]|[[]|[]]");
	rule.format = operaterFormat;
	highlightingRules.append(rule);

	classFormat.setFontWeight(QFont::Bold);
	classFormat.setForeground(Qt::darkMagenta);
	rule.pattern = QRegExp("\\bQ[A-Za-z]+\\b");
	rule.format = classFormat;
	highlightingRules.append(rule);

	numberFormat.setForeground(QColor(240, 0, 240));
	rule.pattern = QRegExp("\\b[0-9]+\\b");
	rule.format = numberFormat;
	highlightingRules.append(rule);

	singleLineCommentFormat.setForeground(QColor(160, 160, 160));
	rule.pattern = QRegExp("//[^\n]*");
	rule.format = singleLineCommentFormat;
	highlightingRules.append(rule);

	multiLineCommentFormat.setForeground(QColor(160, 160, 160));

	quotationFormat.setForeground(Qt::blue);
	rule.pattern = QRegExp("\".*\"");
	rule.format = quotationFormat;
	highlightingRules.append(rule);

	preprocesserFormat.setForeground(QColor(0, 160, 0));
	rule.pattern = QRegExp("#[^\n]*");
	rule.format = preprocesserFormat;
	highlightingRules.append(rule);

	commentStartExpression = QRegExp("/\\*");
	commentEndExpression = QRegExp("\\*/");
}

void Highlighter::highlightBlock(const QString &text)
{
	foreach (const HighlightingRule &rule, highlightingRules) {
		QRegExp expression(rule.pattern);
		int index = expression.indexIn(text);
		while (index >= 0) {
			int length = expression.matchedLength();
			setFormat(index, length, rule.format);
			index = expression.indexIn(text, index + length);
		}
	}
	setCurrentBlockState(0);

	int startIndex = 0;
	if (previousBlockState() != 1)
		startIndex = commentStartExpression.indexIn(text);

	while (startIndex >= 0) {
		int endIndex = commentEndExpression.indexIn(text, startIndex);
		int commentLength;
		if (endIndex == -1) {
			setCurrentBlockState(1);
			commentLength = text.length() - startIndex;
		} else {
			commentLength = endIndex - startIndex
							+ commentEndExpression.matchedLength();
		}
		setFormat(startIndex, commentLength, multiLineCommentFormat);
		startIndex = commentStartExpression.indexIn(text, startIndex + commentLength);
	}
}
